/****************************************************************
 ** Product  :   HP Subscriber Network Application Policy
 ** Module   :   gr-manager
 ** Date: Apr 10, 2015               
 ** Author: Chen Zhenhua
 ** (C) Copyright 2015, Hewlett-Packard Company, All Rights Reserved.
 ** This software is the proprietary information of HP, Inc.  
 ** Use is subject to license terms.
 *****************************************************************
 ** Description:   
 **   gr-manager utility class 
 **  
 ****************************************************************/
package com.hp.snap.gr.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.hp.snap.gr.exception.ActionException;
import com.hp.snap.gr.model.StatusInfo;
import com.hp.snap.gr.model.jaxb.ParameterType;

/**
 * gr-manager utility class.
 *
 * <P>
 * Version: 3.3 <br>
 * Author: Chen Zhenhua
 * Date: Apr 10, 2015
 * 
 * </P>
 *
 **/
public class Utils {

    private static Logger logger = LoggerFactory.getLogger(Utils.class);
    private static final String STATUS_INFO_LABEL_FILE = "status_info_label.properties";

    public static boolean isEmpty(String str) {
        return (str == null) || (str.trim().length() < 1);
    }

    public static String convertMap2Json(Map map) {
        Gson gson = new Gson();
        String json = gson.toJson(map);
        logger.debug("Map convert to a JSON string is:" + json);
        return json;
    }

    private static String formatKeyString(String keyStr) {
        keyStr = keyStr.trim();
        if (keyStr.startsWith("[")) keyStr = keyStr.substring(1);
        if (keyStr.endsWith("]")) keyStr = keyStr.substring(0, keyStr.length() - 1);

        return keyStr;
    }

    public static String getConfigurationValue(String keyStr) {
        String configValue = GRMConfigManager.getGrLocalConfig().get(keyStr);
        if (configValue == null)
            configValue = GRMConfigManager.getGrGlobalConfig().get(keyStr);
        return (configValue == null) ? "" : configValue;
    }

    public static String getConfigurationValue(String node, String keyStr) {
        keyStr = "[" + formatKeyString(node) + "]/" + keyStr;
        return getConfigurationValue(keyStr);
    }

    public static String getHostIP(String siteName, String hostId) {
        return getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + siteName + "/HOST/" + hostId, Constants.CFG_GRG_HOST_IP);
    }

    public static String getGRHostIP(String siteName) {
        String hostId = getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + siteName, Constants.CFG_GRG_SITE_GR_HOST);
        return getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + siteName + "/HOST/" + hostId, Constants.CFG_GRG_HOST_IP);
    }

    public static String getVEMHostIP(String siteName) {
        String hostId = getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + siteName + "/" +
                Constants.CFG_GRG_VOLTDB, Constants.CFG_GRG_VEM_HOST);
        return getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + siteName + "/HOST/" + hostId, Constants.CFG_GRG_HOST_IP);
    }

    public static String[] getMultiConfigurationValue(String keyStr) {
        List<String> _valLst = new ArrayList<String>();
        int seq = 0;
        String configValue = GRMConfigManager.getGrGlobalConfig().get(keyStr);
        while (configValue != null) {
            _valLst.add(configValue);
            seq++;
            configValue = GRMConfigManager.getGrGlobalConfig().get(keyStr + seq);
        }
        String[] values = _valLst.toArray(new String[0]);
        return values;
    }

    public static String[] getMultiConfigurationValue(String node, String keyStr) {
        keyStr = "[" + formatKeyString(node) + "]/" + keyStr;
        return getMultiConfigurationValue(keyStr);
    }

    public static Map<String, String> contructParamMap(List<ParameterType> paramlst) {
        Map<String, String> paramMap = new HashMap<String, String>();
        for (ParameterType param : paramlst) {
            paramMap.put(param.getName(), param.getVal() != null ? param.getVal() : param.getValue());
        }
        return paramMap;
    }

    public static String getCorrespondSiteName(String siteName) {
        String master_slave = getConfigurationValue(Constants.CFG_GRG_ROOT,
                Constants.CFG_GRG_MASTER_SLAVE_RELATION);
        String s2 = null;
        String[] strs = master_slave.split("\\|");
        for (String s : strs) {
            int _index1 = s.indexOf(':');
            int index = s.indexOf(siteName);
            if (index != -1 && _index1 != index) {
                if (index < _index1) {
                    s2 = s.substring(_index1 + 1);
                } else {
                    s2 = s.substring(0, _index1);
                }
            }
        }
        return s2;
    }

    public static boolean checkSlaveSite(String siteName) {
        boolean isSlaveSite = false;
        String master_slave = getConfigurationValue(Constants.CFG_GRG_ROOT, Constants.CFG_GRG_MASTER_SLAVE_RELATION);
        String[] strs = master_slave.split("\\|");
        for (String sites : strs) {
            String[] s2 = sites.split(":");
            if (s2[1].equals(siteName)) {
                isSlaveSite = true;
                break;
            }
        }
        return isSlaveSite;
    }

    public static boolean checkMasterSite(String siteName) {
        boolean isMasterSite = false;
        String master_slave = getConfigurationValue(Constants.CFG_GRG_ROOT, Constants.CFG_GRG_MASTER_SLAVE_RELATION);
        String[] strs = master_slave.split("\\|");
        for (String sites : strs) {
            String[] s2 = sites.split(":");
            if (s2[0].equals(siteName)) {
                isMasterSite = true;
                break;
            }
        }
        return isMasterSite;
    }
    
    public static boolean checkLocalGRStatusIsStopped(){
        boolean grStatus = true;
        String GR_STATUS_FILE_PREFIX = ".SNAP-GR-Status.";
        String runSiteName = Utils.getConfigurationValue(Constants.CFG_GRL_DEPLOY_NAME);
        String _sshUser = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + runSiteName, Constants.CFG_GRG_SITE_SSH_USER);
        String _keyFile = Constants.SSH_PATH + File.separator + Constants.SSH_KEY_FILE;
        String _hostIP = Utils.getGRHostIP(runSiteName);
        String _grStatusFilePath = Constants.USER_HOME + File.separator + "GR";
        SSHTools ssh = new SSHTools(_sshUser, _keyFile);
        String result = "";
        try {
            result = ssh.cmd(_hostIP, "ls -alt " + _grStatusFilePath);
            //.cmd(_host, command);
        } catch (Exception e) {
            // e.printStackTrace();
            logger.error(e.toString());
        }
        int status = ssh.getExitStatusOfCommandResult(result);
        if (logger.isDebugEnabled()) {
            logger.debug("execute getting local SGM status command status is:{}", status);
        }
        String resultStr = ssh.getCommandOutput(result);
        String stats = "STOPPED";
        try {
            LineNumberReader r = new LineNumberReader(new StringReader(resultStr));
            for (String line = r.readLine(); line != null; line = r.readLine()) {
                int index = line.indexOf(GR_STATUS_FILE_PREFIX);
                if (index >= 0) {
                    String filename = line.substring(index);
                    stats = filename.replace(GR_STATUS_FILE_PREFIX, "").toUpperCase();
                    break;
                }
            }
        } catch (IOException e) {
            logger.error("read the local SGM status failed!");
        }
        if (logger.isDebugEnabled()) {
            logger.debug("getting the local SGM status is:{}", stats);
        }
        ssh.closeAll();
        if("SLAVE".equalsIgnoreCase(stats)){
            grStatus = false;
        }
        return grStatus;
    }

    public static String getHost(String hosts) {
        String[] strs = hosts.split("\\|");
        return strs[0];
    }

    /**
     * get the all hosts name and its ip address in a site.
     *
     * @param siteName
     * @return
     */
    public static Map<String, Map<String, Object>> getAllHostsInSite(String siteName) {
        Map<String, Map<String, Object>> siteHostsMap = new HashMap<String, Map<String, Object>>();

        Map<String, String> globalConfig = GRMConfigManager.getGrGlobalConfig();

        String siteSshUser = Utils.getConfigurationValue(siteName, Constants.CFG_GRG_SITE_SSH_USER);

        String keyPrefix = "[" + Constants.CFG_GRG_ROOT + "/" + siteName + "/HOST/";
        for (String key : globalConfig.keySet()) {
            if (key.startsWith(keyPrefix) && key.endsWith("]")) {
                Map<String, Object> map = new HashMap<String, Object>();
                String hostname = Utils.getConfigurationValue(key, Constants.CFG_GRG_HOST_NAME);
                map.put(Constants.CFG_GRG_HOST_NAME, hostname);
                map.put(Constants.CFG_GRG_HOST_IP, Utils.getConfigurationValue(key, Constants.CFG_GRG_HOST_IP));

                String hostSshUser = Utils.getConfigurationValue(key, Constants.CFG_GRG_HOST_SSH_USER);
                if (StringUtils.isEmpty(hostSshUser)) {
                    hostSshUser = siteSshUser;
                }

                map.put(Constants.CFG_GRG_HOST_SSH_USER, hostSshUser);
                map.put(Constants.CFG_GRG_HOST_FILES, Utils.getMultiConfigurationValue(key, Constants.CFG_GRG_HOST_FILES));

                siteHostsMap.put(hostname, map);
            }
        }

        return siteHostsMap;
    }

    public static void printInputParameters(Map<String, Object> inputParams) {
        StringBuffer str = new StringBuffer();
        str.append("Input Parameter is: \n");
        Iterator<Map.Entry<String, Object>> its = inputParams.entrySet().iterator();
        while (its.hasNext()) {
            Map.Entry<String, Object> it = its.next();
            str.append("   " + it.getKey() + "=" + it.getValue() + "\n");
        }
        logger.debug(str.toString());
    }

    public static void printOutputParameters(Map<String, Object> outputParams) {
        StringBuffer str = new StringBuffer();
        str.append("Output Parameter is: \n");
        Iterator<Map.Entry<String, Object>> its = outputParams.entrySet().iterator();
        while (its.hasNext()) {
            Map.Entry<String, Object> it = its.next();
            str.append("   " + it.getKey() + "=" + it.getValue() + "\n");
        }
        logger.debug(str.toString());
    }

    public static Map<String, Integer> getSSTypeCounter(Set<String> ssNames) {
        Map<String, Integer> ssTypeMap = new HashMap<String, Integer>();
        for (String ssName : ssNames) {
            String ssType = getSSType(ssName);
            if (ssTypeMap.get(ssType) == null) {
                ssTypeMap.put(ssType, 0);
            }
        }
        return ssTypeMap;
    }

    public static void printSSTypeCounter(Map<String, Integer> ssTypeMap) {
        for (String ssType : ssTypeMap.keySet()) {
            if (logger.isDebugEnabled()) {
                logger.debug("SSType is {}, its active counter:{}", new Object[]{ssType, ssTypeMap.get(ssType)});
            }
        }
    }

    public static String getCronjobStatus(String command) {
        String cronStatus = Constants.STATUS_CRON_JOB_DISABLE;
        try {
            CmdResult result = new CmdResult();
            int rs = CmdUtils.runShellScript("crontab -l", result);
            if (rs == 0) {
                String cronJobs = result.getStdout().toString();
                LineNumberReader r = new LineNumberReader(new StringReader(cronJobs));
                int rowCount = 0;
                for (String line = r.readLine(); line != null; line = r.readLine()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("exist cron job:{}", line);
                    }
                    if (line.endsWith(command)) {
                        cronStatus = Constants.STATUS_CRON_JOB_ENABLE;
                        break;
                    }
                }

            } else if (rs == 1) {
                logger.warn("Do not found cron job. unRegister operation ignore!");

            }
        } catch (Exception e) {
            logger.error("handler the checking cron job error, the exception is:{}", e.getMessage());
        }
        return cronStatus;
    }

    public static String getRemoteCronjobStatus(String command) throws ActionException {
        String cronStatus = Constants.STATUS_CRON_JOB_DISABLE;
        String result = "";
        String currentSite = Utils.getConfigurationValue(Constants.CFG_GRL_DEPLOY_NAME);
        String runSite = Utils.getCorrespondSiteName(currentSite);

        String runCommandHost = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + runSite, Constants.CFG_GRG_SITE_GR_HOST);
        String runCommandSSHUser = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + runSite, Constants.CFG_GRG_SITE_SSH_USER);
        String runCommandHostIP = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + runSite + "/HOST/" + runCommandHost, Constants.CFG_GRG_HOST_IP);
        if (logger.isDebugEnabled()) {
            logger.debug("runCommandHost is:{}, runCommandSSHUser is:{}, runCommandHostIP is:{}", new Object[]{runCommandHost, runCommandSSHUser, runCommandHostIP});
        }
        SSHTools ssh = new SSHTools(runCommandSSHUser, Constants.SSH_PATH + File.separator + Constants.SSH_KEY_FILE);
        try {
            result = ssh.cmd(runCommandHostIP, "crontab -l");
        } catch (Exception e) {
            logger.error("Connect remote session server failed!, do not get the remote cron job status, Exception is:{}", e.getCause());
            return null;
        }
        int status = ssh.getExitStatusOfCommandResult(result);
        String resultStr = ssh.getCommandOutput(result);
        if (logger.isDebugEnabled()) {
            logger.debug("Get the cron job is:{}", resultStr);
        }
        if (status != 0) {
            logger.error("getting remote cron job status script failed!");
            return Constants.STATUS_CRON_JOB_DISABLE;
        }

        try {
            LineNumberReader r = new LineNumberReader(new StringReader(
                    resultStr));
            for (String line = r.readLine(); line != null; line = r.readLine()) {
                if (line.endsWith(command)) {

                    cronStatus = Constants.STATUS_CRON_JOB_ENABLE;
                    break;
                }
            }
        } catch (IOException e) {
            logger.error("handle the session server status result failed!, exception is:{}", e.getCause());
            return null;
        }

        return cronStatus;
    }

    @SuppressWarnings("unchecked")
    public static void printStatusInfo(StatusInfo obj) throws Exception {
        Class<StatusInfo> statusClass = (Class<StatusInfo>) obj.getClass();
        Field fields[] = statusClass.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            String fieldName = field.getName();
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            Method getMethod = statusClass.getMethod(getMethodName, new Class[]{});
            Object value = getMethod.invoke(obj, new Object[]{});
            if (value != null)
                Constants.CONSOLE.info((String) value);
        }
    }

    public String[] getSSForStatus(boolean remote) throws ActionException {
        String runSite = "";
        String result = "";
        if (remote) {
            String currentSite = Utils.getConfigurationValue(Constants.CFG_GRL_DEPLOY_NAME);
            runSite = Utils.getCorrespondSiteName(currentSite);
        } else {
            runSite = Utils.getConfigurationValue(Constants.CFG_GRL_DEPLOY_NAME);
        }
        String runCommandHost = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + runSite, Constants.CFG_GRG_SITE_GR_HOST);
        String runCommandSSHUser = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + runSite, Constants.CFG_GRG_SITE_SSH_USER);
        String runCommandHostIP = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + runSite + "/HOST/" + runCommandHost, Constants.CFG_GRG_HOST_IP);
        SSHTools ssh2 = new SSHTools(runCommandSSHUser, Constants.SSH_PATH + File.separator + Constants.SSH_KEY_FILE);
        try {
            result = ssh2.cmd(runCommandHostIP, "source .bash_profile && " + Constants.USER_GR_ARTIFACT + "/SNAP-GR-Tools.sh GETSS4STATUS | grep 'SGT_OUTPUT:' | awk -F':' '{print $2}'");
        } catch (Exception e) {
            logger.error("Connect remote master session server failed!, Exceptio is:{}", e.getMessage());
            throw new ActionException(e.getMessage(), e.getCause());
        }
        int status = ssh2.getExitStatusOfCommandResult(result);
        String resultStr = ssh2.getCommandOutput(result);
        if (logger.isDebugEnabled()) {
            logger.debug("Get the session server is:{}", resultStr);
        }
        logger.info("=============Get the session server is:{}", resultStr);
        if (status != 0) {
            logger.error("execute the getting session server list shell script failed!");
            throw new ActionException("execute the getting session server list shell script failed!");
        }
        String[] ssStringArray = resultStr.split(" ");
        return ssStringArray;
    }

    public static Map<String, Integer> getSSCounterForActive() {
        Map<String, Integer> ssCounterMap = new HashMap<String, Integer>();
        String ssCounters = getConfigurationValue(Constants.CFG_GRG_SESSION_SERVER, Constants.CFG_GRG_SESSION_SERVER_STATUS_CANDIDATES);
        String[] sessionSers = ssCounters.split(",");
        for (String sessionSer : sessionSers) {
            String[] sessionCounter = sessionSer.split(":");
            if (sessionCounter.length == 2) {
                ssCounterMap.put(sessionCounter[0], Integer.parseInt(sessionCounter[1]));
            }
        }
        return ssCounterMap;
    }

    public static boolean swapMasterSlaveRole(String masterSlave, String grgRoot) throws ActionException {

        String oldMasterSlave = Utils.getConfigurationValue(grgRoot, masterSlave);
        if (!StringUtils.isEmpty(oldMasterSlave)) {
            String newMasterSlave = swapRole(oldMasterSlave);
            if (logger.isDebugEnabled()) {
                logger.debug("the old master_slave is:{} new master_slave after swaping roles is:{}", new Object[]{oldMasterSlave, newMasterSlave});
            }
            SSConfigUtils.replaceConfig(Constants.CFG_GRG_ROOT, Constants.CFG_GRG_MASTER_SLAVE_RELATION, oldMasterSlave, newMasterSlave);
        } else {
            logger.error("The Master_Slave configuration does not exist!!");
            throw new ActionException("The Master_Slave configuration does not exist!!");
        }
        return true;
    }

    private static String swapRole(String masterSlaveStr) {
        StringBuffer strBuf = new StringBuffer();
        String str = masterSlaveStr;
        String[] ss1 = str.split("\\|");
        for (String s1 : ss1) {
            String[] ss2 = s1.split(":");
            strBuf.append(ss2[1]).append(":").append(ss2[0]).append("|");
        }

        return strBuf.toString().substring(0, strBuf.length() - 1);
    }

    /**
     * @param ssName SPRP/snap460b26.chn.hp.com/RTC_SPRPROXY1
     * @return
     */
    public static String getSSType(String ssName) {
        String[] strs = ssName.split("/");
        return strs[0];
    }

    public static Map<String, String> getStatusInfoLabelMap() throws Exception {
        Map<String, String> statusInfoLabelMap = new HashMap<String, String>();
        Properties prop = new Properties();
        String statuslabelFile = Constants.USER_GR_CONF + File.separator + STATUS_INFO_LABEL_FILE;
        InputStream is = null;
        try {
            File file = new File(statuslabelFile);
            if (file.exists()) {
                is = new FileInputStream(file);
            } else {
                is = ClassLoader.getSystemResourceAsStream(STATUS_INFO_LABEL_FILE);
            }

            prop.load(is);

            Set<String> propKeys = prop.stringPropertyNames();

            for (String propKey : propKeys) {
                statusInfoLabelMap.put(propKey, prop.getProperty(propKey).trim());
            }
        } finally {
            if (is != null) {
                is.close();
            }
        }
        return statusInfoLabelMap;
    }

    public static String replaceString(String srcStr, Map<String, String> strMap) {
        for (String key : strMap.keySet()) {
            String val = strMap.get(key);
            srcStr = srcStr.replaceAll(key, val);
        }
        return srcStr;
    }

    public static String stackTraceToString(Throwable e) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : e.getStackTrace()) {
            sb.append(element.toString());
            sb.append("\n");
        }
        return sb.toString();
    }
    
    public static String maskEIUMPasswd(String str){
    	int lcoal1 = str.indexOf("EIUM_PWD=");
        String str2 = str.substring(lcoal1);
        int local2 = str2.indexOf("\"");
        return (str.replace(str2.substring(0,local2), "EIUM_PWD=******"));
    }
    
    public static File generateKeyFile(String sshKey) {

        File keyFile = new File(".isa_key");
        try {
            FileWriter fw = new FileWriter(keyFile);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.append(sshKey);
            bw.close();
            fw.close();

        } catch (IOException e) {
            logger.error("generate key file failed! " + e.toString());

        }
        return keyFile;

    }
    
}
